export default class AniCanvas {
  /**
   * 构造函数，初始化画布和上下文
   * @param {String} id - 画布元素的ID
   */
  constructor(id) {
    this.id = id;
    this.canvasNode = null;
    this.canvas = null;
    this.ctx = null;
    this.lrCenter = null; // 左右居中位置
    this.tbCenter = null; // 上下居中位置
    this.canvasImg = null; // 画布生成的图片
    this.defaultText = {
      x: 0,
      y: 0,
      fontSize: 16,
      color: '#000000',
      align: 'left',
      space: 0,
      lineAlign: 'top'
    };

    // 使用 IIFE 和 async/await 初始化 canvas
    (async () => {
      await this.creatCanvas2d();
    })();
  }

  /**
   * 创建并初始化2D画布
   */
  async creatCanvas2d() {
    await new Promise((resolve) => {
      wx.createSelectorQuery()
          .select("#" + this.id)
          .fields({ node: true, size: true })
          .exec((e) => {
            this.initCanvas(e[0]);
            resolve();
          });
    });
  }

  /**
   * 初始化画布和上下文
   * @param {Object} canvasNode - 画布节点信息
   */
  initCanvas(canvasNode) {
    this.canvasNode = canvasNode;
    this.canvas = canvasNode.node;
    this.ctx = this.canvas.getContext("2d");
    this.lrCenter = this.canvasNode.width / 2;
    this.tbCenter = this.canvasNode.height / 2;
    this.width = this.canvasNode.width;
    this.height = this.canvasNode.height;
    this.setDpr();
  }

  /**
   * 设置设备像素比，优化画布显示效果
   * @param {Number} [scale] - 可选的缩放比例
   */
  setDpr(scale) {
    const dpr = scale || wx.getSystemInfoSync().pixelRatio;
    this.canvas.width = this.width * dpr;
    this.canvas.height = this.height * dpr;
    this.ctx.scale(dpr, dpr);
  }

  /**
   * 设置画布背景色
   * @param {String} color - 背景颜色
   */
  setBg(color) {
    this.ctx.fillStyle = color;
    this.ctx.fillRect(0, 0, this.width, this.height);
  }

  /**
   * 在画布上绘制图片
   * @param {String} url - 图片URL
   * @param {Number} left - 图片左上角的x坐标
   * @param {Number} top - 图片左上角的y坐标
   * @param {Number} width - 图片宽度
   * @param {Number} [height] - 图片高度，可选
   * @returns {Promise} 加载并绘制图片的Promise
   */
  setImage(url, left, top, width, height) {
    return new Promise((resolve) => {
      const img = this.canvas.createImage();
      img.src = url;
      img.onload = () => {
        const naturalHeight = (width / img.width) * img.height;
        this.ctx.drawImage(img, left, top, width, height || naturalHeight);
        resolve({
          endTop: top + (height || naturalHeight),
          endLeft: left + width,
          img,
        });
      };
    });
  }

  /**
   * 将文本分割为适应最大宽度的多行文本
   * @param {String} text - 待分割的文本
   * @param {Number} maxWidth - 最大宽度限制
   * @returns {Object} 包含分割后的文本数组和文本总宽度
   */
  getTextArr(text, maxWidth) {
    if (!maxWidth) {
      const textWidth = this.ctx.measureText(text).width;
      return { textArr: [text], allWidth: textWidth };
    }

    let arr = [];
    let str = '';
    [...text].forEach((char, i) => {
      str += char;
      const metrics = this.ctx.measureText(str);
      if (metrics.width >= maxWidth || i === text.length - 1) {
        arr.push(str);
        str = '';
      }
    });

    return { textArr: arr, allWidth: metrics.width };
  }

  /**
   * 在画布上绘制文本
   * @param {Object|String} arg1 - 文本参数对象或文本字符串
   * @param {...any} args - 其他参数，如果第一个参数是字符串
   * @returns {Object} 绘制文本的结果，包括结束位置和文本数组
   */
  setText(arg1, ...args) {
    let params;
    if (typeof arg1 === 'object') {
      params = { ...this.defaultText, ...arg1 };
    } else {
      params = { ...this.defaultText, text: arg1, ...args[0] };
    }

    const { text, x, y, fontSize, color, align, space, lineAlign, maxWidth, maxLine } = params;
    if (!text) throw new Error("未定义文字");

    this.ctx.font = `${fontSize}px normal`;
    this.ctx.fillStyle = color;
    this.ctx.textAlign = align;

    const { textArr } = this.getTextArr(text, maxWidth);
    let finalTextArr = maxLine ? textArr.slice(0, maxLine) : textArr;

    let endTop = y;
    let endLeft = x;

    finalTextArr.forEach((line, i) => {
      const textY = y + i * (fontSize + space);
      this.ctx.fillText(line, x, textY);
      endTop = textY;
      endLeft = align === 'left' ? x + this.ctx.measureText(line).width : x;
    });

    return { endTop, endLeft, textArr: finalTextArr };
  }

  /**
   * 将当前画布内容导出为图片
   * @returns {Promise<String>} 导出图片的Promise，解析为图片路径
   */
  async createImg() {
    const query = wx.createSelectorQuery();
    const canvasObj = await new Promise((resolve) => {
      query.select('#' + this.id)
          .fields({ node: true, size: true })
          .exec((res) => resolve(res[0].node));
    });
    return new Promise((resolve) => {
      wx.canvasToTempFilePath({
        canvas: canvasObj,
        success: (res) => {
          this.canvasImg = res.tempFilePath;
          resolve(res.tempFilePath);
        },
        fail: resolve
      }, this);
    });
  }

  /**
   * 保存当前画布内容为图片到相册
   * @returns {Promise} 保存操作的Promise
   */
  async saveImg() {
    const url = this.canvasImg || await this.createImg();
    return new Promise((resolve, reject) => {
      wx.saveImageToPhotosAlbum({
        filePath: url,
        success: resolve,
        fail: reject
      });
    });
  }

  /**
   * 静态方法：保存指定图片到相册
   * @param {String} url - 图片路径
   * @returns {Promise} 保存操作的Promise
   */
  static saveImg(url) {
    return new Promise((resolve, reject) => {
      wx.saveImageToPhotosAlbum({
        filePath: url,
        success: resolve,
        fail: reject
      });
    });
  }
}
